
package au.com.lastweekend.jim.swing;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;

import javax.swing.AbstractAction;

public class PropertyBoundToggleAction extends AbstractAction {

    private static final long serialVersionUID = 1L;

    public class PropertyBindingException extends RuntimeException {

        private static final long serialVersionUID = 1L;

        public PropertyBindingException(String msg, Exception e) {

            super(msg, e);
        }

    }
    private Object bean;
    private String boundProperty;
    private Method isMethod;
    private Method setMethod;
    private Method addListenerMethod;

    public PropertyBoundToggleAction(String name, Object bean, String property) {

        super(name);
        this.bean = bean;
        this.boundProperty = property;
        try {
            isMethod = bean.getClass().getMethod("is" + boundProperty);
            setMethod = bean.getClass().getMethod("set" + boundProperty, boolean.class);
            addListenerMethod = bean.getClass().getMethod("addPropertyChangeListener", String.class, PropertyChangeListener.class);

        } catch (Exception e) {

            throw new PropertyBindingException("Bad property " + property + " for class " + bean.getClass().getName(), e);
        }

    }

    public void actionPerformed(ActionEvent e) {

        try {
            Boolean isSelected = getPropertyValue();
            setMethod.invoke(bean, new Object[]{!isSelected});
        } catch (Exception ex) {
            throw new PropertyBindingException("Bad property " + boundProperty + " for class " + bean.getClass().getName(), ex);
        }
    }

    public Boolean getPropertyValue() {

        try {
            return (Boolean) isMethod.invoke(bean, (Object[]) null);
        } catch (Exception ex) {
            throw new PropertyBindingException("Bad property " + boundProperty + " for class " + bean.getClass().getName(), ex);
        }
    }

    public void bindPropertyChangeListener(PropertyChangeListener listener) {

        try {
            addListenerMethod.invoke(bean, (new Object[]{boundProperty, listener}));
        } catch (Exception ex) {
            throw new PropertyBindingException("Bad property " + boundProperty + " for class " + bean.getClass().getName(), ex);
        }

    }
}
